<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>hdfiujash</p>
    <p>hdfiujash
        <span>我是span</span>
        <span>我是span</span>
    </p>

    <script src="../lib/jquery/jquery.min.js"></script>
    <script>

        /*1. 请列出三大家族成员，并写出其检测盒子宽高的区别？

            1. offset家族，包括offsetWidth/Height/Top/Left/Parent，xx.offsetWidth/Height表示xx这个元素在空间的实际大小（content+padding+border）；

            2. scroll家族，包括scrollWidth/Height/Top/Left，xx.scrollWidth/Height表示xx这个元素如果具有滚动条，Width（padding-left+content），Height（padding-top + content + padding-bottom）；

            3. client家族，包括clientWidth/Height/Top/Left，xx.clientWidth/Height表示xx这个元素的（padding+content）。

        2. 写出获取滚动条卷入高度的方法

            1. window.offsetPageY；

            2. document.body.scrollTop 文件头无<!DOCTYPE html>；

            3. document.ducumentElement.scrollTop html5 的写法。

        3. 如何判断一个变量是数组类型，请写出你已知的判断方法

            1. arr instanceof Array  // true/false
            2. Object.prototype.toString.call(arr) // [Object Array]...

        4. 请写出获取元素行内样式、内联样式、外联样式的方法

            1. 获取行内样式：dom.style.xx;
            2. 获取内联样式：dom.getComputedStyle('xx')   $(dom).css('xx')   $(dom).prop('xx')这个是表单
            3. 获取外联样式：同2

        5. 请写出HTML5新的存储值属性？并列出详细的方法

            localStorage:  localStorage.getItem('xx')获取  /  setItem('xx', json串)设置或修改   /  removeItem('xx') 移除  /  clear()清空

        6. 请写一个正则表达式，校验日期格式：年-月-日  例如：2016-08-20 为true 2016/08/20 为false

            '/\d+-0\d-\d{2}'.test(str)

        7. 事件委托是什么？为什么要使用它？

        ​		事件委托是把本应该由某个元素触发的事件，将它绑定在其父级元素上，通过某些限制条件（event.target.tagName == 'xx'）来间接触发。

        ​		这样做：

            1. 如果多个子元素要触发类似的事件，事件委托可以减少事件绑定次数
            2. 在子元素重新加载时，事件委托可以防止事件丢失

        8. 请说出你对防抖和节流的理解

            这两个的出发点都是为了降低事件触发频率

            防抖：定时器版：写一个防抖函数，利用定时器，将事件的触发的函数包裹起来，重复触发时，不断清除定时器，使其始终不能执行包裹在定时器里面的事件的触发函数，只有当等待规定的wait时间内，事件不触发，才能执行一次事件的触发函数，然后循环。

            节流：定时器版：写一个防抖函数，利用定时器，将事件的触发的函数包裹起来，wait时间内，不管触发多少次防抖函数，事件的触发函数只会执行一次，不断循环。节流函数还可以用日期来写。

        9. 随机数范围 [6-56]，请用两种方式实现

            1. Math.floor( Math.random() * 51 ) + 6
            2. Math.round( Math.random() * 50 ) + 6

        10. 简述你对call、apply、bind方法的理解

            1. 对于call方法，xx.call（obj , a, b, c...）目的是改变xx函数内部this，用obj来替代他，a, b, c...是xx函数的参数，注意的是，xx.call()会执行一次xx函数，如果不传参数，默认obj=window，第一位参数一定会被当成obj解析。
            2. 对于apply方法，xx.apply（obj, [a, b, c...]）用法与注意同call一模一样，只是传参会以数组的形式进行。
            3. bind方法，yy = xx.bind（obj, a, b, c...）xx.bind()会创造一个新函数，obj替换掉xx里的this，a, b, c...为xx里的参数（第一位，第二位，...），bind方法永远的冻结了他们，yy（d, e...）调用的时候不可以再设置a, b, c...了。

        ## 判断输出值

        1）

        var uname = "张三";
        function fn(){
        var uname = "李四";
        function gn(){
            return this.uname;
        }
        return gn();
        }

        fn();  // 李四


        2）

        var a = 100;
        function fn(){
        console.log(a);  // 100
        a = 10;
        console.log(a);  // 10
        }
        fn();
        console.log(a);  // 10

        3）

        var name = 'Tom';
        (function() {
        if (typeof name == 'undefined') {
            var name = 'Jack';
            console.log('Goodbye ' + name);
        } else {
            console.log('Hello ' + name);
        }
        })();
        // Goodbye Jack
        

        4)

        ```js
        "11" == String("11");  // true
        "11" === String("11");  // true
        String('11') == new String('11');  // true
        String('11') === new String('11');  // true
        ```

        5)

        function Foo() {
        Foo.a = function() {
            console.log(1)
        }
        this.a = function() {
            console.log(2)
        }
        }
        Foo.prototype.a = function() {
        console.log(3)
        }
        Foo.a = function() {
        console.log(4)
        }

        Foo.a();  // 4
        let obj = new Foo();
        obj.a();  // 2
        Foo.a();  // 1
        */

        // 1. 用事件委托的方式实现点击页面内任何 p 标签，标签内文本颜色变蓝。如果标签内部带有任何子元素，则子元素内文本颜色变红。

        document.body.onclick = function () {
            if (event.target.tagName == 'P') {
                event.target.style.color = 'blue';
                if (event.target.children[0]) {
                    $(event.target).children().css('color', 'red')
                }
            }
        }
 


        // 2. 请写出对象浅拷贝的方法及深拷贝的方法

        var obj = {
            name: '哈哈',
            age: 30,
            sex: '男',
            skills: ['h5', 'css3', 'JS', 'jQ'],
            say() {
                console.log('滚呐');
            }
        }
        
        // 浅拷贝
        var obj1 = Object.assign({}, obj); // 无法复刻引用数据类型
        var obj2 = JSON.parse(JSON.stringify(obj)); // 丢失方法
        var obj3 = {}; // 笨笨方法
        for (const i in obj) {
            obj3[i] = obj[i]
        }

        // console.log(obj1, obj1.skills === obj.skills); // true
        // console.log(obj2, obj2.say === obj.say); // false
        // console.log(obj3, obj3.skills === obj.skills); // true
        
        // 深拷贝
        var obj4 = deepClone(obj);
        console.log(obj4, obj4.say === obj.say); // true
        console.log(obj4, obj4.skills === obj.skills); // true
        
        function deepClone(obj) {
            var toString = Object.prototype.toString;
            // 如果是空直接返回
            if (!(toString.call(obj).search('Null') == -1)) {
                return
            }
            var obj1 = (toString.call(obj).search('Object') == -1) ? [] : {};
            for (const i in obj) {
                // 如果是对象类型
                if (typeof obj[i] == 'object') {
                    obj1[i] = deepClone(obj[i])
                } else {
                    obj1[i] = obj[i];
                }
            }
            return obj1
        }


        // 3. 请写一个函数，将数字的整数位以千分位分隔 例如: fn(1234567) ==> "1,234,567"  fn(12345.67) ==> "12,345.67"

        var num =3432224325.4343;
        console.log(change(num));

        function change(num) {
            // 方法1
            var str = String(num);
            var arr = str.split('.');
            // 将整数部分倒装
            str0 = arr[0].split('').reverse().join('');
            // 加上，
            str0 = str0.replace(/\w{3}/g, '$&,');
            // 倒回去
            str0 = str0.split('').reverse().join('');
            // 返回字符串
            return str0 + '.' + arr[1]

            // 方法2 愚蠢
            /*
            var str = String(num);
            var arr = str.split('.');
            // 如果num整数位小于4位
            if (arr[0].length < 4) {
                return str
            } else {
                // 将整数部分转化为数组
                var arr0 = arr[0].split('');
                // 加上，
                for (var i = arr0.length; i > 0; i -= 3) {
                    arr0.splice(i, 0, ',')
                }
                // 去掉尾部多余的一个，并返回整个字符串
                return arr0.slice(0, arr0.length-1).join('') + '.' + arr[1]
            }
            */
        }

        // 4. 给定一个数组，它的第i个元素是一支给定股票第i天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票一次)，设计一个算法来计算你所能获取的最大利润。注意;你不能在买入股票前卖出股票。
        var arr = [7, 1, 5, 3, 6, 4];
        console.log(getMoney(arr));

        function getMoney(arr) {
            var max = 0;
            for (var i = 0; i < arr.length; i++) {
                for (var j = i + 1; j < arr.length; j++) {
                    if (arr[j] - arr[i] > max) {
                        max = arr[j] - arr[i];
                    }
                }
            }
            return max
        }


        // 5. 封装方法将字符串转化为驼峰命名 例如：`var s1 = "get-element-by-id"  ===>  getElementById`

        console.log(getMount('get-element-by-id'));
        function getMount(str) {
            // 替换-以及后面的一个字母
            return str.replace(/-\w/g, function (str) {
                return str.slice(1).toUpperCase()
            })
        }

        // 6. 实现一个方法render，可以将字符串中双花括号变量变成传入的对象对应属性名的属性值，如下所示
        var template = '我是{{name}},年龄{{age}},性别{{sex}}',
            data = {
                name: '姓名',
                age: 18
            }
        console.log(render(template, data));

        function render(template, data) {
            // 方法1
            template = template.replace(/\{\{\w+\}\}/g, function (str) {
                var arr = str.match(/\w+/g);
                return data[arr[0]]
            })
            return template

            // 方法2 愚蠢
            /*
            // 分段
            var arr = template.split(',');
            for (var i = 0; i < arr.length; i++) {
                // 去掉{{}}
                arr[i] = arr[i].replace(/{{(\w+)}}/, ',$1')
            }
            // 拼接为字符串
            var str = '';
            for (var i = 0; i < arr.length; i++) {
                var temp = arr[i].split(',');
                console.log(temp);
                str += temp[0] + data[temp[1]] + ','
            }
            return str
            */
        }
    </script>
</body>
</html>